package com.app.oral.service.impl

import com.app.oral.dao.ExerciseRecordMapper
import com.app.oral.dao.UserMapper
import com.app.oral.model.ExerciseRecord
import com.app.oral.model.ExerciseMode
import com.app.oral.model.ExerciseStage
import com.app.oral.model.ExerciseStatus
import com.app.oral.model.ExpressionScoreDetails
import com.app.oral.model.ReadingScoreDetails
import com.app.oral.model.QuestionAnswer
import com.app.oral.model.ReadingAnswer
import com.app.oral.model.UserType
import com.app.oral.service.ExerciseRecordService
import com.app.oral.service.ExerciseStatistics
import com.app.oral.service.PaperStatistics
import com.app.oral.service.ClassStatistics
import com.app.oral.service.WeChatCloudFileDeleteService
import com.app.oral.model.FileDeleteSourceType
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal
import java.math.RoundingMode
import java.time.LocalDateTime
import java.util.*

/**
 * 练习记录服务实现
 */
@Service
@Transactional
class ExerciseRecordServiceImpl(
    private val exerciseRecordMapper: ExerciseRecordMapper,
    private val userMapper: UserMapper,
    private val weChatCloudFileDeleteService: WeChatCloudFileDeleteService
) : ExerciseRecordService {
    
    companion object {
        private val logger = LoggerFactory.getLogger(ExerciseRecordServiceImpl::class.java)
    }
    
    override fun createOrGet(userId: Long, paperId: Long, mode: ExerciseMode): ExerciseRecord {
        logger.info("创建或获取练习记录: userId={}, paperId={}, mode={}", userId, paperId, mode)
        
        // 先尝试查询现有记录
        val existingRecord = exerciseRecordMapper.selectByUserPaperMode(userId, paperId, mode)
        if (existingRecord != null) {
            logger.info("找到现有练习记录: id={}", existingRecord.id)
            return existingRecord
        }
        
        // 创建新记录
        val defaultDialogue = (1..5).map { QuestionAnswer(number = it) }
        val defaultListening = (1..5).map { QuestionAnswer(number = it) }
        val newRecord = ExerciseRecord(
            id = UUID.randomUUID().toString(),
            userId = userId,
            paperId = paperId,
            mode = mode,
            status = ExerciseStatus.IN_PROGRESS,
            currentStage = ExerciseStage.READING,
            currentQuestionIndex = 0,
            dialogueAnswers = defaultDialogue,
            listeningAnswers = defaultListening,
            createdAt = LocalDateTime.now(),
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.insert(newRecord)
        logger.info("创建新练习记录成功: id={}", newRecord.id)
        return newRecord
    }
    
    override fun findById(id: String): ExerciseRecord? {
        return exerciseRecordMapper.selectById(id)
    }
    
    override fun findByUserPaperMode(userId: Long, paperId: Long, mode: ExerciseMode): ExerciseRecord? {
        return exerciseRecordMapper.selectByUserPaperMode(userId, paperId, mode)
    }
    
    override fun findByUserId(userId: Long): List<ExerciseRecord> {
        return exerciseRecordMapper.selectByUserId(userId)
    }
    
    override fun findByPaperId(paperId: Long): List<ExerciseRecord> {
        return exerciseRecordMapper.selectByPaperId(paperId)
    }
    
    override fun findCompleted(): List<ExerciseRecord> {
        return exerciseRecordMapper.selectCompleted()
    }
    
    override fun updateReadingResult(
        recordId: String,
        audioFileId: String,
        scoreDetails: ReadingScoreDetails
    ): ExerciseRecord? {
        logger.info("更新短文朗读结果: recordId={}, audioFileId={}", recordId, audioFileId)
        
        val record = exerciseRecordMapper.selectById(recordId) ?: return null
        
        // 如果已有旧的录音文件，删除COS中的旧文件
        record.readingAnswer?.audioFileId?.let { oldFileId ->
            if (oldFileId != audioFileId) {
                logger.info("删除旧的短文朗读音频文件: oldFileId={}", oldFileId)
                val deleteResult = weChatCloudFileDeleteService.deleteFile(oldFileId, FileDeleteSourceType.EXERCISE_RECORD, recordId)
                if (!deleteResult.success) {
                    logger.warn("删除旧音频文件失败: {}", deleteResult.message)
                }
            }
        }
        val updatedRecord = record.copy(
            status = ExerciseStatus.IN_PROGRESS,
            currentStage = ExerciseStage.LISTENING,
            currentQuestionIndex = 1,
            readingAnswer = ReadingAnswer(
                completed = true,
                audioFileId = audioFileId,
                scoreDetails = scoreDetails,
                attemptTime = LocalDateTime.now()
            ),
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("短文朗读结果更新成功")
        return updatedRecord
    }
    
    override fun updateListeningResult(
        recordId: String,
        listeningIndex: Int,
        audioFileId: String,
        score: BigDecimal
    ): ExerciseRecord? {
        logger.info("更新视听应答结果: recordId={}, index={}, score={}", recordId, listeningIndex, score)
        
        if (listeningIndex !in 1..5) {
            throw IllegalArgumentException("视听应答索引必须在1-5之间")
        }
        
        val record = exerciseRecordMapper.selectById(recordId) ?: return null
        
        // 删除旧的视听应答音频文件
        val oldFileId = record.listeningAnswers.getOrNull(listeningIndex - 1)?.audioFileId
        
        oldFileId?.let { oldFile ->
            if (oldFile != audioFileId) {
                logger.info("删除旧的视听应答{}音频文件: oldFileId={}", listeningIndex, oldFile)
                val deleteResult = weChatCloudFileDeleteService.deleteFile(oldFile, FileDeleteSourceType.EXERCISE_RECORD, recordId)
                if (!deleteResult.success) {
                    logger.warn("删除旧音频文件失败: {}", deleteResult.message)
                }
            }
        }
        
        val newListeningList = record.listeningAnswers.mapIndexed { idx, ans ->
            if (idx == listeningIndex - 1) ans.copy(
                completed = true,
                audioFileId = audioFileId,
                score = score,
                attemptTime = LocalDateTime.now()
            ) else ans
        }
        val nextStage = if (listeningIndex >= 5) ExerciseStage.DIALOGUE else ExerciseStage.LISTENING
        val updatedRecord = record.copy(
            status = ExerciseStatus.IN_PROGRESS,
            currentStage = nextStage,
            currentQuestionIndex = 1 + newListeningList.count { it.completed },
            listeningAnswers = newListeningList,
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("视听应答结果更新成功")
        return updatedRecord
    }


    override fun updateDialogueResult(
        recordId: String,
        dialogueIndex: Int,
        audioFileId: String,
        score: BigDecimal
    ): ExerciseRecord? {
        logger.info("更新情景问答结果: recordId={}, index={}, score={}", recordId, dialogueIndex, score)
        
        if (dialogueIndex !in 1..5) {
            throw IllegalArgumentException("对话索引必须在1-5之间")
        }
        
        val record = exerciseRecordMapper.selectById(recordId) ?: return null
        
        // 删除旧的对话音频文件
        val oldFileId = record.dialogueAnswers.getOrNull(dialogueIndex - 1)?.audioFileId
        
        oldFileId?.let { oldFile ->
            if (oldFile != audioFileId) {
                logger.info("删除旧的情景问答{}音频文件: oldFileId={}", dialogueIndex, oldFile)
                val deleteResult = weChatCloudFileDeleteService.deleteFile(oldFile, FileDeleteSourceType.EXERCISE_RECORD, recordId)
                if (!deleteResult.success) {
                    logger.warn("删除旧音频文件失败: {}", deleteResult.message)
                }
            }
        }
        
        val newDialogueList = record.dialogueAnswers.mapIndexed { idx, ans ->
            if (idx == dialogueIndex - 1) ans.copy(
                completed = true,
                audioFileId = audioFileId,
                score = score,
                attemptTime = LocalDateTime.now()
            ) else ans
        }
        val nextStage = if (dialogueIndex >= 5) ExerciseStage.EXPRESSION else ExerciseStage.DIALOGUE
        val updatedRecord = record.copy(
            status = ExerciseStatus.IN_PROGRESS,
            currentStage = nextStage,
            currentQuestionIndex = 6 + newDialogueList.count { it.completed },
            dialogueAnswers = newDialogueList,
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("情景问答{}结果更新成功", dialogueIndex)
        return updatedRecord
    }
    
    override fun updateExpressionResult(
        recordId: String,
        audioFileId: String,
        score: BigDecimal,
        scoreDetails: ExpressionScoreDetails
    ): ExerciseRecord? {
        logger.info("更新话题简述结果: recordId={}, score={}", recordId, score)

        val record = exerciseRecordMapper.selectById(recordId) ?: return null

        // 如果已有旧的录音文件，删除COS中的旧文件
        record.expressionAnswer?.audioFileId?.let { oldFileId ->
            if (oldFileId != audioFileId) {
                logger.info("删除旧的话题简述音频文件: oldFileId={}", oldFileId)
                val deleteResult = weChatCloudFileDeleteService.deleteFile(oldFileId, FileDeleteSourceType.EXERCISE_RECORD, recordId)
                if (!deleteResult.success) {
                    logger.warn("删除旧音频文件失败: {}", deleteResult.message)
                }
            }
        }

        val updatedRecord = record.copy(
            status = ExerciseStatus.COMPLETED,
            currentStage = ExerciseStage.EXPRESSION,
            expressionAnswer = (record.expressionAnswer ?: com.app.oral.model.ExpressionAnswer()).copy(
                completed = true,
                audioFileId = audioFileId,
                score = score,
                scoreDetails = scoreDetails,
                attemptTime = LocalDateTime.now()
            ),
            updatedAt = LocalDateTime.now(),
            completedAt = LocalDateTime.now()
        )

        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("话题简述结果更新成功")

        // 自动计算总分
        return calculateTotalScore(recordId)
    }

    override fun updateExpressionScore(
        recordId: String,
        score: BigDecimal,
        scoreDetails: ExpressionScoreDetails
    ): ExerciseRecord? {
        logger.info("修改话题简述分数: recordId={}, score={}", recordId, score)

        val record = exerciseRecordMapper.selectById(recordId) ?: return null

        // 检查是否已有话题简述答案
        if (record.expressionAnswer == null) {
            logger.warn("话题简述答案不存在，无法修改分数: recordId={}", recordId)
            throw IllegalStateException("话题简述答案不存在，无法修改分数")
        }

        // 如果传入的suggestedScore为null，保留原有的suggestedScore值
        val finalScoreDetails = if (scoreDetails.suggestedScore == null && record.expressionAnswer!!.scoreDetails != null) {
            scoreDetails.copy(suggestedScore = record.expressionAnswer!!.scoreDetails!!.suggestedScore)
        } else {
            scoreDetails
        }

        // 只更新分数和评分详情，保留原有的音频文件ID和其他信息
        val updatedRecord = record.copy(
            expressionAnswer = record.expressionAnswer!!.copy(
                score = score,
                scoreDetails = finalScoreDetails
            ),
            updatedAt = LocalDateTime.now()
        )

        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("话题简述分数修改成功")

        // 自动重新计算总分
        return calculateTotalScore(recordId)
    }
    
    override fun calculateTotalScore(recordId: String): ExerciseRecord? {
        logger.info("计算总分: recordId={}", recordId)

        val record = exerciseRecordMapper.selectById(recordId) ?: return null

        // 计算总分逻辑
        val readingScore = record.parseReadingScoreDetails()?.suggestedScore ?: BigDecimal.ZERO
        val listeningScores = record.listeningAnswers.mapNotNull { it.score }
        val dialogueScores = record.dialogueAnswers.mapNotNull { it.score }
        val expressionScore = record.expressionAnswer?.score ?: BigDecimal.ZERO

        // 视听应答总分（5题总分）
        val listeningTotal = listeningScores.fold(BigDecimal.ZERO) { acc, s -> acc + s }

        // 情景问答总分（5题总分）
        val dialogueTotal = dialogueScores.fold(BigDecimal.ZERO) { acc, s -> acc + s }

        // 总分 = 短文朗读分数 + 视听应答总分 + 情景问答总分 + 话题简述分数
        val totalScore = readingScore + listeningTotal + dialogueTotal + expressionScore

        val updatedRecord = record.copy(
            totalScore = totalScore,
            updatedAt = LocalDateTime.now()
        )

        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("总分计算完成: reading={}, listening={}, dialogue={}, expression={}, total={}",
            readingScore, listeningTotal, dialogueTotal, expressionScore, totalScore)
        return updatedRecord
    }
    
    override fun markCompleted(recordId: String): ExerciseRecord? {
        logger.info("标记练习完成: recordId={}", recordId)
        
        val record = exerciseRecordMapper.selectById(recordId) ?: return null
        
        val updatedRecord = record.copy(
            status = ExerciseStatus.COMPLETED,
            // 保持在表达阶段
            currentStage = ExerciseStage.EXPRESSION,
            completedAt = LocalDateTime.now(),
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.updateById(updatedRecord)
        logger.info("练习标记完成成功")
        return updatedRecord
    }
    
    override fun delete(recordId: String): Boolean {
        logger.info("删除练习记录: recordId={}", recordId)
        
        // 先获取记录以提取音频文件ID
        val record = exerciseRecordMapper.selectById(recordId)
        if (record != null) {
            // 提取所有音频文件ID并删除COS文件
            val audioFileIds = weChatCloudFileDeleteService.extractAudioFileIds(record)
            if (audioFileIds.isNotEmpty()) {
                logger.info("删除练习记录关联的COS文件: recordId={}, fileIds={}", recordId, audioFileIds)
                val deleteResult = weChatCloudFileDeleteService.deleteFiles(audioFileIds, FileDeleteSourceType.EXERCISE_RECORD, recordId)
                if (!deleteResult.success) {
                    logger.warn("删除COS文件失败: {}", deleteResult.message)
                }
            }
        }
        
        val result = exerciseRecordMapper.deleteById(recordId) > 0
        logger.info("删除练习记录结果: {}", if (result) "成功" else "失败")
        return result
    }
    
    override fun getUserStatistics(userId: Long): ExerciseStatistics {
        logger.info("获取用户练习统计: userId={}", userId)
        
        val allRecords = exerciseRecordMapper.selectByUserId(userId)
        val practiceRecords = allRecords.filter { it.mode == ExerciseMode.PRACTICE }
        val testRecords = allRecords.filter { it.mode == ExerciseMode.TEST }
        val completedRecords = allRecords.filter { it.isCompleted() }
        
        val averageScore = if (completedRecords.isNotEmpty()) {
            val totalScore = completedRecords.mapNotNull { it.totalScore }
                .fold(BigDecimal.ZERO) { acc, score -> acc + score }
            totalScore.divide(BigDecimal(completedRecords.size), 2, BigDecimal.ROUND_HALF_UP)
        } else null
        
        return ExerciseStatistics(
            totalRecords = allRecords.size,
            practiceRecords = practiceRecords.size,
            testRecords = testRecords.size,
            completedRecords = completedRecords.size,
            averageScore = averageScore
        )
    }
    
    override fun getPaperStatistics(paperId: Long): PaperStatistics {
        logger.info("获取试卷练习统计: paperId={}", paperId)
        
        val allRecords = exerciseRecordMapper.selectByPaperId(paperId)
        val practiceRecords = allRecords.filter { it.mode == ExerciseMode.PRACTICE }
        val testRecords = allRecords.filter { it.mode == ExerciseMode.TEST }
        val completedRecords = allRecords.filter { it.isCompleted() }
        
        val scores = completedRecords.mapNotNull { it.totalScore }
        val averageScore = if (scores.isNotEmpty()) {
            scores.fold(BigDecimal.ZERO) { acc, score -> acc + score }
                .divide(BigDecimal(scores.size), 2, BigDecimal.ROUND_HALF_UP)
        } else null
        
        val highestScore = scores.maxOrNull()
        
        return PaperStatistics(
            totalAttempts = allRecords.size,
            practiceAttempts = practiceRecords.size,
            testAttempts = testRecords.size,
            completedAttempts = completedRecords.size,
            averageScore = averageScore,
            highestScore = highestScore
        )
    }
    
    override fun getClassStatistics(classId: Long): ClassStatistics {
        // 获取班级总学生数
        val totalStudents = userMapper.countStudentsByClassId(classId)
        
        // 获取班级内所有学生
        val classStudents = userMapper.findStudentsByClassId(classId)
        val studentIds = classStudents.map { it.id!! }
        
        if (studentIds.isEmpty()) {
            return ClassStatistics(
                totalStudents = totalStudents,
                activeStudents = 0,
                totalRecords = 0,
                completedRecords = 0,
                practiceRecords = 0,
                testRecords = 0,
                averageScore = null
            )
        }
        
        // 获取班级所有练习记录
        val allRecords = exerciseRecordMapper.selectByUserIds(studentIds)
        val completedRecords = allRecords.filter { it.isCompleted() }
        val practiceRecords = allRecords.filter { it.mode == ExerciseMode.PRACTICE }
        val testRecords = allRecords.filter { it.mode == ExerciseMode.TEST }
        
        // 计算有练习记录的学生数
        val activeStudentIds = allRecords.map { it.userId }.toSet()
        val activeStudents = activeStudentIds.size
        
        // 计算平均分
        val scores = completedRecords.mapNotNull { it.totalScore }
        val averageScore = if (scores.isNotEmpty()) {
            scores.fold(BigDecimal.ZERO) { acc, score -> acc + score }
                .divide(BigDecimal(scores.size), 2, BigDecimal.ROUND_HALF_UP)
        } else null
        
        return ClassStatistics(
            totalStudents = totalStudents,
            activeStudents = activeStudents,
            totalRecords = allRecords.size,
            completedRecords = completedRecords.size,
            practiceRecords = practiceRecords.size,
            testRecords = testRecords.size,
            averageScore = averageScore
        )
    }
    
    override fun resetRecord(recordId: String): ExerciseRecord? {
        logger.info("重置练习记录: recordId={}", recordId)
        
        val record = exerciseRecordMapper.selectById(recordId) ?: return null
        
        // 删除相关的COS音频文件
        val audioFileIds = weChatCloudFileDeleteService.extractAudioFileIds(record)
        if (audioFileIds.isNotEmpty()) {
            logger.info("重置时删除练习记录关联的COS文件: recordId={}, fileIds={}", recordId, audioFileIds)
            val deleteResult = weChatCloudFileDeleteService.deleteFiles(audioFileIds, FileDeleteSourceType.EXERCISE_RECORD, recordId)
            if (!deleteResult.success) {
                logger.warn("重置时删除COS文件失败: {}", deleteResult.message)
            }
        }
        
        // 重置记录到初始状态
        val resetRecord = record.copy(
            status = ExerciseStatus.IN_PROGRESS,
            currentStage = ExerciseStage.READING,
            currentQuestionIndex = 0,
            readingAnswer = null,
            listeningAnswers = (1..5).map { QuestionAnswer(number = it) },
            dialogueAnswers = (1..5).map { QuestionAnswer(number = it) },
            expressionAnswer = null,
            totalScore = null,
            completedAt = null,
            updatedAt = LocalDateTime.now()
        )
        
        exerciseRecordMapper.updateById(resetRecord)
        logger.info("练习记录重置完成: recordId={}", recordId)
        
        return resetRecord
    }
}
